package com.licheedev.adplayer;

import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.licheedev.adplayer.data.AdData;
import com.licheedev.myutils.LogPlus;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class AdPlayer {

    /** 无意义的下标，如果是这个，表示未使用下标 */
    public static final int POSITION_NO_MEANING = -1;

    protected final Handler mHandler;
    protected final AdView mAdView;
    protected final AdViewController mController;

    private final List<AdData> mData = new ArrayList<>();

    /** 当前播放广告的下标 */
    private int mCurrentAdPos = POSITION_NO_MEANING;
    private AdData mCurrentAd;

    /**
     * （设置列表后）第一次加载
     */
    private final AtomicBoolean mFirstLoad = new AtomicBoolean(true);

    /**
     * 已经开始播放任务
     */
    private boolean mStarted;
    /**
     * 已经暂停任务
     */
    private boolean mPaused;

    /**
     * 播放列表的ID，用来区分新旧播放列表
     */
    private int mPlayListId = 0;
    private int mSignFactor = 0;

    private String mPlayingItemSign;

    protected OnClickAdListener mOnClickAdListener;
    protected OnPlayListener mOnPlayListener;

    /**
     * (图片)播放时间
     */
    private long mImageDuration = 5000L;
    /**
     * (视频、音频)播放时间
     */
    private long mVideoDuration = 0L;
    /**
     * 限制视频/音频播放时间，默认不限制
     */
    private boolean mLimitVideoDuration = false;
    /**
     * 当强制图片/视频/音频播放相同的时间时，是否允许最后一次播放完整
     */
    private boolean mAllowFinalVideoFullPlay = true;
    /**
     * 播放错误后，播放下一首的延时
     */
    private long mErrorDelay = mImageDuration;

    public AdPlayer(AdView adView) {
        mHandler = new Handler();
        mAdView = adView;
        mController = new AdViewController(adView, this);
    }

    //<editor-fold desc="配置属性">

    /**
     * 设置音量
     *
     * @param left
     * @param right
     */
    public void setVolume(float left, float right) {
        mController.setVolume(left, right);
    }

    /**
     * （图片）播放时间
     *
     * @return
     */
    public long getImageDuration() {
        return mImageDuration;
    }

    /**
     * 设置（图片）播放时间
     *
     * @param duration (图片)播放时间
     */
    public void setImageDuration(long duration) {
        mImageDuration = duration;
    }

    /**
     * （视频、音频）播放时间
     *
     * @return
     */
    public long getVideoDuration() {
        return mVideoDuration;
    }

    /**
     * 设置（视频、音频）播放时间
     *
     * @param videoDuration
     */
    public void setVideoDuration(long videoDuration) {
        mVideoDuration = videoDuration;
    }

    /**
     * 设置视频播放规则
     *
     * @param limitVideoDuration 限制音视频播放特定时间{@link #getVideoDuration()}
     * 对于音视频，如果文件时长&lt;duration，则重播，如果文件时长 &gt;=duration，则播放duration后直接播放下一首
     * @param allowFinalVideoFullPlay 只有limitVideoDuration为true时才有用。表示是否允许最后一次播放完整
     */
    public void setVideoRule(boolean limitVideoDuration, boolean allowFinalVideoFullPlay) {
        mLimitVideoDuration = limitVideoDuration;
        mAllowFinalVideoFullPlay = allowFinalVideoFullPlay;
    }

    /**
     * 限制音视频播放特定时间{@link #getVideoDuration()}
     * 于音视频，如果文件时长&lt;duration，则重播，如果文件时长 &gt;=duration，则播放duration后直接播放下一首
     *
     * @return
     */
    public boolean isLimitVideoDuration() {
        return mLimitVideoDuration;
    }

    /**
     * 只有limitVideoDuration为true时才有用。表示是否允许最后一次播放完整
     *
     * @return
     */
    public boolean isAllowFinalVideoFullPlay() {
        return mAllowFinalVideoFullPlay;
    }

    /**
     * 播放错误后，播放下一首的延时
     *
     * @return
     */
    public long getErrorDelay() {
        return mErrorDelay;
    }

    /**
     * 设置播放错误后，播放下一首的延时
     *
     * @param errorDelay
     */
    public void setErrorDelay(long errorDelay) {
        mErrorDelay = errorDelay;
    }

    //</editor-fold>

    public int getCurrentAdPos() {
        return mCurrentAdPos;
    }

    protected void setCurrentAdPos(int currentAdPos) {
        mCurrentAdPos = currentAdPos;
    }

    public AdData getCurrentAd() {
        return mCurrentAd;
    }

    protected void setCurrentAd(AdData currentAd) {
        mCurrentAd = currentAd;
    }

    /**
     * 设置播放数据
     *
     * @param data 播放数据源
     * @param toPlayPosition 要播放的曲目位置
     */
    public void setNewData(List<? extends AdData> data, int toPlayPosition) {
        assertMainThread("setNewData");
        // 停止播放
        stop();
        resetPlayListInfo();

        if (data == null || data.size() < 1) {
            mData.clear();
            mCurrentAdPos = POSITION_NO_MEANING;
            mCurrentAd = null;
            mController.showNone();
        } else {
            mData.clear();
            mData.addAll(data);
            mCurrentAdPos = (toPlayPosition >= size() || toPlayPosition < 0) ? 0 : toPlayPosition;
            // 因为下面要拦截并配置下一个，所以这里下标再减1
            mCurrentAdPos--;
            configNextAutoPlayItem();
        }

        // 当设置好数据后
        boolean handled = false;
        if (mOnPlayListener != null) {
            handled = mOnPlayListener.onSetNewData(mData);
        }
        if (handled) {
            return;
        }

        start(true);
    }

    /**
     * 设置播放数据,从0开始播放
     *
     * @param data 播放数据源
     */
    public void setNewData(List<? extends AdData> data) {
        setNewData(data, 0);
    }

    /** 广告列表大小 */
    public int size() {
        return mData.size();
    }

    public List<AdData> getData() {
        return mData;
    }

    /** 设置播放下标到下一个 */
    protected final void setPositionToNext() {
        int next = mCurrentAdPos + 1;
        if (next >= size()) {
            next = 0;
        }
        mCurrentAdPos = next;
        mCurrentAd = Util.getItem(mData, mCurrentAdPos);
    }

    /**
     * 配置下一个自动播放的数据，如果播放的条目有限制，可以通过重写这方法，来手动跳过某些播放条目
     */
    protected void configNextAutoPlayItem() {
        setPositionToNext();
    }

    protected final Runnable mPlayNextTask = new Runnable() {
        @Override
        public void run() {
            configNextAutoPlayItem();
            start(false);
        }
    };

    /** 播放下一条条目 */
    protected void playNextItem(long delay) {
        removeCallbacks();
        if (delay > 0) {
            mHandler.postDelayed(mPlayNextTask, delay);
        } else {
            mPlayNextTask.run();
        }
    }

    /**
     * 强制手动播放下一曲
     */
    public void playNextManually() {
        assertMainThread("playNextManually");
        if (size() == 0) {
            return;
        }

        removeCallbacks();
        setPositionToNext();
        start(true);
    }

    /**
     * 播放指定位置的曲目
     *
     * @param position 项目下标，如果下标
     */
    public void playItem(int position) {
        assertMainThread("playItem");
        if (size() == 0) {
            return;
        }
        removeCallbacks();
        mCurrentAdPos = (position >= size() || position < 0) ? 0 : position;
        mCurrentAd = Util.getItem(mData, mCurrentAdPos);
        start(true);
    }

    /** 播放其他条目，用于处理非{@link #mData}中的数据，这时候{@link #mCurrentAdPos} 无效 */
    public void playOtherItem(AdData data) {
        assertMainThread("playOtherItem");
        removeCallbacks();
        mCurrentAd = data;
        start(false);
    }

    /**
     * 播放特定条目
     *
     * @param adData
     * @param force 强制播放，无视是否已经暂停
     * @param startTime
     */
    protected void startItem(@Nullable AdData adData, boolean force, long startTime) {
        // 生成播放签名
        mPlayingItemSign = generatePlayingItemSign(adData);
        
        if (adData == null) {
            return;
        }
        mStarted = true;

        if (force) {
            mPaused = false;
        }
        // 已经开启且没有暂停，才播放
        if (force || (mStarted && !mPaused)) {
            mController.playItem(adData, mPlayingItemSign, startTime);
        }
    }

    /**
     * 开始播放当前项目
     *
     * @param force 强制播放，无视是否已经暂停
     */
    public void start(boolean force) {
        startItem(mCurrentAd, force, SystemClock.uptimeMillis());
    }

    /** 开始播放当前项目 */
    public void start() {
        start(false);
    }

    /** 停止播放 */
    public void stop() {
        removeCallbacks();
        // 清空播放签名
        clearPlayingItemSign();
        mController.stop();
        mStarted = false;
        mPaused = false;
    }

    /**
     * 恢复播放
     *
     * @param resetRender 重置渲染器，默认false；如果界面生命周期，如onResume()等后发现界面卡住了，可以尝试把这个参数填true重置渲染器，不过可能会导致画面出现一下闪烁。
     */
    public void resume(boolean resetRender) {
        removeCallbacks();
        if (mStarted && mPaused) {
            mPaused = false;
            mPlayingItemSign = generatePlayingItemSign(mCurrentAd);
            mController.resume(mPlayingItemSign, SystemClock.uptimeMillis(), resetRender);
        }
    }

    /**
     * 恢复播放
     *
     * @see {@link #resume(boolean)}
     */
    public void resume() {
        resume(false);
    }

    /**
     * 暂停播放
     */
    public void pause() {
        removeCallbacks();
        // 清空播放签名
        clearPlayingItemSign();
        if (mStarted) {
            mPaused = true;
            mController.pause();
        }
    }

    public void release() {
        removeCallbacks();
        // 清空播放签名
        clearPlayingItemSign();
        mController.destroy();
    }

    /**
     * 更新播放状态
     *
     * @param state
     * @param adData
     * @param startTime
     */
    void updateState(@PlayEvent.Event int state, AdData adData, long startTime) {
        switch (state) {
            case PlayEvent.EVENT_SET_DATASOURCE:
                if (mOnPlayListener != null) {
                    mOnPlayListener.onPreparingAdData(adData, mCurrentAdPos);
                }
                break;
            case PlayEvent.EVENT_IMAGE_PREPARED:
                if (mOnPlayListener != null) {
                    mOnPlayListener.onStartPlay(adData, mCurrentAdPos);
                }
                break;
            case PlayEvent.EVENT_IMAGE_PLAY_COMPLETE: {
                boolean handled = false;
                if (mOnPlayListener != null) {
                    handled = mOnPlayListener.onPlayCompleted(adData, mCurrentAdPos);
                }
                if (handled) {
                    return;
                }
                playNextItem(0);
                break;
            }
            case PlayEvent.EVENT_VIDEO_PREPARED:
                if (mOnPlayListener != null) {
                    mOnPlayListener.onStartPlay(adData, mCurrentAdPos);
                }
                // 如果指定了视频时间，并且不允许最后一次播放完毕
                if (mLimitVideoDuration && !mAllowFinalVideoFullPlay) {
                    long duration = adData.duration() > 0 ? adData.duration() : getVideoDuration();
                    if (duration > 0) {
                        // 每次播放（重播）都会进来一次，所以可能会叠多个延时任务，
                        // 不过因为第一个任务正式运行时（播放下一首），会清掉所有任务，所以不用管这个
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                // 直接播放下一首
                                playNextItem(0);
                            }
                        }, duration);
                    }
                }
                break;
            case PlayEvent.EVENT_VIDEO_PLAY_COMPLETE: {
                boolean handled = false;
                if (mOnPlayListener != null) {
                    handled = mOnPlayListener.onPlayCompleted(adData, mCurrentAdPos);
                }
                if (handled) {
                    return;
                }
                if (mLimitVideoDuration) {
                    long duration = adData.duration() > 0 ? adData.duration() : getVideoDuration();
                    long remainTime = duration - (SystemClock.uptimeMillis() - startTime);
                    // 如果剩余时间够长，才重播，否则播下一首
                    if (remainTime >= 100) {
                        LogPlus.i("重播=" + adData.getURI());
                        startItem(adData, false, startTime);
                        return;
                    }
                }
                // 其他情况，播放下一首
                playNextItem(0);
                break;
            }
            case PlayEvent.EVENT_PLAY_ERROR: {
                boolean handled = false;
                if (mOnPlayListener != null) {
                    handled = mOnPlayListener.onPlayFailed(adData, mCurrentAdPos);
                }
                if (handled) {
                    return;
                }
                playNextItem(mErrorDelay);
                break;
            }
        }
    }

    public boolean isStarted() {
        return mStarted;
    }

    public boolean isPaused() {
        return mPaused;
    }

    /** 重置播放列表信息 */
    protected void resetPlayListInfo() {
        changePlayListId();
        clearPlayingItemSign();
        mFirstLoad.set(true);
    }

    /** 修改播放列表ID */
    protected void changePlayListId() {
        mPlayListId++;
    }

    /**
     * 生成当前条目签名播放条目签名,用于异步回调中来区分是否还在当前条目
     *
     * @return
     */
    protected String generatePlayingItemSign(AdData adData) {
        return mPlayListId
            + "_"
            + SystemClock.uptimeMillis()
            + "_"
            + (++mSignFactor)
            + "_"
            + adData;
    }

    /**
     * 清空播放签名
     */
    protected void clearPlayingItemSign() {
        mPlayingItemSign = generatePlayingItemSign(null);
    }

    /**
     * 判断某广告是否已经过时
     *
     * @param playingItemSign 要判断的广告的播放签名
     * @return true，已过时（已经开始播放其他项目了）；false，没过时（正在播放传入签名的项目）
     */
    boolean isOutData(String playingItemSign) {
        return !playingItemSign.equals(mPlayingItemSign);
    }

    boolean getAndChangeFirstLoad() {
        return mFirstLoad.getAndSet(false);
    }

    boolean isFirstLoad() {
        return mFirstLoad.get();
    }

    /**
     * 移除所有Handler任务
     */
    protected void removeCallbacks() {
        mHandler.removeCallbacksAndMessages(null);
    }

    protected static void assertMainThread(String methodName) {
        if (Looper.getMainLooper().getThread() != Thread.currentThread()) {
            throw new IllegalStateException(
                "Cannot invoke " + methodName + " on a background" + " thread");
        }
    }

    //<editor-fold desc="事件监听">

    /** 点击广告事件监听 */
    public interface OnClickAdListener {

        /**
         * 点击广告
         *
         * @param adData 如果没有数据，则为null
         * @param position 如果没有数据，则为-1
         */
        void onClickAd(@Nullable AdData adData, int position);
    }

    /**
     * 设置点击广告监听
     *
     * @param listener
     */
    public void setOnClickAdListener(@Nullable OnClickAdListener listener) {
        mOnClickAdListener = listener;
        if (listener == null) {
            mAdView.setOnClickListener(null);
        } else {
            mAdView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    listener.onClickAd(mCurrentAd, mCurrentAdPos);
                }
            });
        }
    }

    /** 播放事件监听 */
    public interface OnPlayListener {

        /**
         * 当设置新的广告数据
         *
         * @param adDataList
         * @return 如果返回true，表示拦截设置新数据事件，程序不会自动播放下一个
         */
        boolean onSetNewData(@NonNull List<AdData> adDataList);

        /**
         * 当开始准备（设置）播放数据
         *
         * @param adData
         * @param position
         */
        void onPreparingAdData(AdData adData, int position);

        /**
         * 当开始播放
         *
         * @param adData
         * @param position
         */
        void onStartPlay(AdData adData, int position);

        /**
         * 当播放完毕
         *
         * @param adData
         * @param position
         * @return 如果返回true，表示拦截处理播放完毕事件，程序不会自动播放下一个
         */
        boolean onPlayCompleted(AdData adData, int position);

        /**
         * 当播放失败
         *
         * @param adData
         * @param position
         * @return 如果返回true，表示拦截处理播放失败事件，程序不会自动播放下一个
         */
        boolean onPlayFailed(AdData adData, int position);
    }

    public void setOnOnPlayListener(OnPlayListener listener) {
        mOnPlayListener = listener;
    }
    //</editor-fold>
}
